﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace BostonXNA.InputHandling.Input
{
	class InputHandler
	{
		private GameWindow Window;
		public InputHandler()
		{						
		}

		public InputHandler( GameWindow window )
		{
			Window = window;
			Mouse.WindowHandle = Window.Handle;
		}
		Dictionary<PlayerIndex, KeyboardState> currentKeyboardStates = new Dictionary<PlayerIndex, KeyboardState>();
		Dictionary<PlayerIndex, KeyboardState> previousKeyboardStates = new Dictionary<PlayerIndex, KeyboardState>();
		MouseState currentMouseState, previousMouseState;
		Dictionary<PlayerIndex, GamePadState> currentGamePadStates = new Dictionary<PlayerIndex, GamePadState>();
		Dictionary<PlayerIndex, GamePadState> previousGamePadStates = new Dictionary<PlayerIndex, GamePadState>();

		Dictionary<IInputSequence, Action<PlayerIndex, InputState>> sequences = new Dictionary<IInputSequence, Action<PlayerIndex, InputState>>();

		public void Initialize()
		{
			Mouse.SetPosition( Window.ClientBounds.Center.X, Window.ClientBounds.Center.Y );

			currentKeyboardStates.Add( PlayerIndex.One, Keyboard.GetState( PlayerIndex.One ) );
			currentKeyboardStates.Add( PlayerIndex.Two, Keyboard.GetState( PlayerIndex.Two ) );
			currentKeyboardStates.Add( PlayerIndex.Three, Keyboard.GetState( PlayerIndex.Three ) );
			currentKeyboardStates.Add( PlayerIndex.Four, Keyboard.GetState( PlayerIndex.Four ) );

			previousMouseState = currentMouseState = Mouse.GetState();

			currentGamePadStates.Add( PlayerIndex.One, GamePad.GetState( PlayerIndex.One ) );
			currentGamePadStates.Add( PlayerIndex.Two, GamePad.GetState( PlayerIndex.Two ) );
			currentGamePadStates.Add( PlayerIndex.Three, GamePad.GetState( PlayerIndex.Three ) );
			currentGamePadStates.Add( PlayerIndex.Four, GamePad.GetState( PlayerIndex.Four ) );
		}

		public void Update()
		{
			previousKeyboardStates[PlayerIndex.One] = currentKeyboardStates[PlayerIndex.One];
			previousKeyboardStates[PlayerIndex.Two] = currentKeyboardStates[PlayerIndex.Two];
			previousKeyboardStates[PlayerIndex.Three] = currentKeyboardStates[PlayerIndex.Three];
			previousKeyboardStates[PlayerIndex.Four] = currentKeyboardStates[PlayerIndex.Four];

			previousMouseState = currentMouseState;

			previousGamePadStates[ PlayerIndex.One ] = currentGamePadStates[ PlayerIndex.One ];
			previousGamePadStates[ PlayerIndex.Two ] = currentGamePadStates[ PlayerIndex.Two ];
			previousGamePadStates[ PlayerIndex.Three ] = currentGamePadStates[ PlayerIndex.Three ];
			previousGamePadStates[ PlayerIndex.Four ] = currentGamePadStates[ PlayerIndex.Four ];

			currentKeyboardStates[PlayerIndex.One] = Keyboard.GetState(PlayerIndex.One);
			currentKeyboardStates[PlayerIndex.Two] = Keyboard.GetState(PlayerIndex.Two);
			currentKeyboardStates[PlayerIndex.Three] = Keyboard.GetState(PlayerIndex.Three);
			currentKeyboardStates[PlayerIndex.Four] = Keyboard.GetState(PlayerIndex.Four);

			currentMouseState = Mouse.GetState();

			currentGamePadStates[PlayerIndex.One]= GamePad.GetState( PlayerIndex.One ) ;
			currentGamePadStates[ PlayerIndex.Two]= GamePad.GetState( PlayerIndex.Two ) ;
			currentGamePadStates[PlayerIndex.Three]= GamePad.GetState( PlayerIndex.Three ) ;
			currentGamePadStates[ PlayerIndex.Four ] = GamePad.GetState( PlayerIndex.Four );

			ProcessInput();
		}

		private void ProcessInput()
		{
			// Handle Keyboard Input
			foreach (PlayerIndex player in currentKeyboardStates.Keys)
			{
				var inputState = new InputState()
				{
					Keyboard = new KeyboardInputState()
					{
						Current = currentKeyboardStates[ player ],
						Previous = previousKeyboardStates[ player ]
					},
					Mouse = new MouseInputState()
					{
						Current = currentMouseState,
						Previous = previousMouseState
					},
					GamePad = new GamePadInputState()
					{
						Current = currentGamePadStates[ player ],
						Previous = previousGamePadStates[ player ]
					}
				};
				foreach (var item in sequences)
				{
					var sequence = item.Key;
					if ( sequence.Check( player, inputState ) )
					{
						item.Value( player, inputState );
					}
				}
			}
		}

		public void AddAction(Action<PlayerIndex,InputState> action, Keys key )
		{
			var sequence = new InputSequence();
			sequence.Add( new KeyDownActivity()
			{
				Key = key
			} );
			sequences.Add(sequence, action);
		}

		public void AddAction( Action<PlayerIndex, InputState> action, Buttons button )
		{
			var sequence = new InputSequence();
			sequence.Add( new GamePadButtonDownActivity()
			{
				Button = button
			} );
			sequences.Add( sequence, action );
		}

		public void AddAction( Action<PlayerIndex, InputState> action, InputSequence sequence )
		{
			sequences.Add(sequence, action);
		}

		public void AddAction( Action<PlayerIndex, InputState> action, MouseMove movement )
		{
			var sequence = new InputSequence();
			sequence.Add( new MouseMoveActivity()
			{
				Direction = movement
			} );
			sequences.Add( sequence, action );
		}
	}
}
